﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Drawing;
using System.Data;

using OpenChart.PublicUnits;
using OpenChart.Entities;

namespace OpenChart.DrawChart
{
    class DrawingLogarithmLineChart:AbsDrawingChart
    {
        private double _minLogYValue;//最大值所对应的对数值
        private double _maxLogYValue;//最小值所对应的对数值

        /// <summary>
        /// 绘制数据
        /// </summary>
        protected override void DrawData()
        {
            foreach (var item in this.ChartArea.Series)
            {
                this.DrawOneSeries(item);
            }
        }

        /// <summary>
        /// 绘制一个Series
        /// </summary>
        /// <param name="item">Series</param>
        protected virtual void DrawOneSeries(Series item)
        {
            List<PointF> points = new List<PointF>();
            PointF tempPoint;
            double tempXValue, tempYValue;
            foreach (DataRow row in this.ChartArea.Data.Rows)
            {
                tempXValue = ChartHelper.GetDoubleValue(row[this.ChartArea.XValueMember], this.ChartArea.AxisX.IntervalType);
                tempYValue = ChartHelper.GetDoubleValue(row[item.YValueMember], this.ChartArea.AxisY1.IntervalType);
                tempPoint = this.GetPoint(tempXValue, tempYValue);
                points.Add(tempPoint);
            }
            if (points.Count() > 0)
            {
                Pen pen = new Pen(item.Color, item.Width);
                this.Graphics.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias;
                this.Graphics.DrawLines(pen, points.ToArray());
                this.Graphics.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.Default;
            }
        }

        //根据数据计算坐标点位置
        protected PointF GetPoint(double xValue, double yValue)
        {
            yValue = Math.Log(yValue, this.ChartArea.BaseNumber);

            float xValuePerPixel = (float)(_maxXValue - _minXValue) / (this.CanvasWidth - CON_LEFT_RANGE - CON_RIGTH_RANGE);
            float yValuePerPixel = (float)(_maxLogYValue - _minLogYValue) / (this.CanvasHeight - CON_DOWN_RANGE - CON_UP_RANGE);

            PointF point = new PointF();
            point.X = (float)(CON_LEFT_RANGE + (xValue - _minXValue) / xValuePerPixel);
            point.Y = (float)(this.CanvasHeight - CON_DOWN_RANGE - (yValue - _minLogYValue) / yValuePerPixel);

            return point;
        }

        /// <summary>
        /// 绘制纵坐标
        /// </summary>
        protected override void DrawYScale()
        {
            this.CalculateLogMaxMinValue();

            float scaleCount = (float)Math.Ceiling((_maxLogYValue - _minLogYValue) / this.ChartArea.AxisY1.Interval.Value);//刻度的数量
            float scaleWidth = (this.CanvasHeight - CON_UP_RANGE - CON_DOWN_RANGE) / scaleCount;//每个刻度所占用的长度

            string lable = string.Empty;
            float position = this.CanvasHeight - CON_DOWN_RANGE;
            double powerNumber = _minLogYValue;
            for (int i = 0; i <= scaleCount; i++)
            {
                double lableValue = Math.Pow(this.ChartArea.BaseNumber, powerNumber);
                lable = lableValue.ToString();
                this.DrawOneYScaleAndGrid(position, scaleWidth, lable);
                if (i < scaleCount)//最后一条线不用画了
                {
                    DrawSmallScale(position, lable);
                }
                position -= scaleWidth;
                powerNumber += this.ChartArea.AxisY1.Interval.Value;
            }
        }

        //计算最大值和最小值对应的对数值
        private void CalculateLogMaxMinValue()
        {
            _minLogYValue = Math.Log(_minYValue, this.ChartArea.BaseNumber);
            _maxLogYValue = Math.Log(_maxYValue,this.ChartArea.BaseNumber);
            if (_minLogYValue == _maxLogYValue)
            {
                _maxLogYValue += 0.5;
                _minLogYValue -= 0.5;
            }
            _minLogYValue = Math.Floor(_minLogYValue);
            _maxLogYValue = Math.Ceiling(_maxLogYValue);
        }

        //绘制一个纵坐标刻度和网格线
        private void DrawOneYScaleAndGrid(double position, double scaleWidth, string lable)
        {
            //
            //绘制网格
            //
            if (this.ChartArea.AxisY1.ShowGrid)
            {
                if (position != this.CanvasHeight - CON_DOWN_RANGE)
                {
                    Pen pen = new Pen(this.ChartArea.AxisY1.Grid.LineColor);
                    pen.DashStyle = ChartHelper.GetDashStyle(this.ChartArea.AxisY1.Grid.LineStyle);
                    this.Graphics.DrawLine(pen, CON_LEFT_RANGE, (float)position, this.CanvasWidth - CON_RIGTH_RANGE, (float)position);
                }
            }
            else
            {
                Pen pen = new Pen(this.ChartArea.AxisLineColor);
                this.Graphics.DrawLine(pen, CON_LEFT_RANGE, (float)position, CON_LEFT_RANGE + 10, (float)position);
            }
            //
            //绘制坐标值
            //
            double number = 0d;
            if (double.TryParse(lable, out number))
            {
                if (number > 9999)
                {
                    lable = number.ToString("e2");
                }
            }
            RectangleF rect = new RectangleF(5, (float)(position - scaleWidth / 2), CON_LEFT_RANGE - 5, (float)scaleWidth);
            StringFormat stringFormat = new StringFormat();
            stringFormat.Alignment = StringAlignment.Far;
            stringFormat.LineAlignment = StringAlignment.Center;
            Brush brush = new SolidBrush(this.ChartArea.AxisLineColor);
            this.Graphics.DrawString(lable, new Font("宋体", 12), brush, rect, stringFormat);
        }

        //绘制不等宽的小坐标
        private void DrawSmallScale(float position, string lable)
        {
            double labelValue = Convert.ToDouble(lable); ;
            double drawValue = labelValue;
            for (int i = 1; i < this.ChartArea.BaseNumber - 1; i++)
            {
                drawValue += labelValue;

                float yValuePerPixel = (float)(_maxLogYValue - _minLogYValue) / (this.CanvasHeight - CON_DOWN_RANGE - CON_UP_RANGE);
                float drawYPixel = (float)(this.CanvasHeight - CON_DOWN_RANGE - (Math.Log(drawValue, this.ChartArea.BaseNumber) - _minLogYValue) / yValuePerPixel);
                this.Graphics.DrawLine(new Pen(this.ChartArea.AxisLineColor, this.ChartArea.AxisLineWidth), CON_LEFT_RANGE, drawYPixel, CON_LEFT_RANGE + 5, drawYPixel);
            }
        }

        #region 绘制分割线

        /// <summary>
        /// 绘制分割线
        /// </summary>
        protected override void DrawPartingLines()
        {
            foreach (var item in this.ChartArea.PartingLines)
            {
                this.DrawPartingLine(item);
            }
        }

        //绘制分割线
        private void DrawPartingLine(PartingLine item)
        {
            //
            //绘制横线
            //
            float position = this.GetYPixelPositionByValue(item.YValue);
            Pen pen = new Pen(item.LineColor, item.LineWidth);
            pen.DashStyle = ChartHelper.GetDashStyle(item.LineStyle);
            this.Graphics.DrawLine(pen, CON_LEFT_RANGE, position, this.CanvasWidth - CON_RIGTH_RANGE, position);

            //
            //绘制刻度显示值
            //
            string lable = string.Empty;
            if (item.YValue > 9999)
            {
                lable = item.YValue.ToString("e2");
            }
            else
            {
                lable = item.YValue.ToString();
            }
            RectangleF rect = new RectangleF(5, position - 10, CON_LEFT_RANGE - 5, 20);
            StringFormat stringFormat = new StringFormat();
            stringFormat.Alignment = StringAlignment.Far;
            stringFormat.LineAlignment = StringAlignment.Center;
            Brush brush = new SolidBrush(item.LineColor);
            this.Graphics.DrawString(lable, new Font("宋体", 12), brush, rect, stringFormat);

        }

        //根据Y轴值返回像素位置
        private float GetYPixelPositionByValue(double value)
        {
            float yValuePerPixel = (float)(_maxLogYValue - _minLogYValue) / (this.CanvasHeight - CON_DOWN_RANGE - CON_UP_RANGE);
            float drawYPixel = (float)(this.CanvasHeight - CON_DOWN_RANGE - (Math.Log(value, this.ChartArea.BaseNumber) - _minLogYValue) / yValuePerPixel);
            return drawYPixel;
        }

        #endregion
    }
}
